<?php

namespace ApiSdk\Kwaixiaodian\Servers;

use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Config\Repository;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Redis\RedisManager;

class AccessTokenService extends BaseService
{

    /**
     * Notes: 生成授权地址
     * author: lfy
     * Date: 2021/10/11
     * Time: 10:41
     * @param $state
     * @param string $scope
     * @return string
     */
    public function firstAuthAppToken($state, $scope = '')
    {
        $scope = $scope ? $scope : "merchant_shop,merchant_user,merchant_order,merchant_item,merchant_logistics";
        return $this->getAuthorizedUrl($state, $scope);
    }

    /**
     * Notes:获取token
     * author: lfy
     * Date: 2021/10/11
     * Time: 10:42
     * @param string $code
     * @param string|null $grant_type
     * @return bool|void
     * @throws GuzzleException
     */
    public function getToken(string $code, string $grant_type = 'code')
    {
        $this->addCommonParams('grant_type', $grant_type);
        $this->addCommonParams('code', $code);
        return $this->getTokenData();
    }

    /**
     * Notes: 刷新token
     * author: lfy
     * Date: 2021/10/11
     * Time: 10:17
     * @param string $refresh_token
     * @return bool|void
     * @throws GuzzleException
     */
    public function refreshToken(string $refresh_token = '')
    {
        $this->addCommonParams('grant_type', 'refresh_token');
        $this->addCommonParams('refresh_token', $refresh_token);
        return $this->getTokenData('/oauth2/refresh_token');
    }

    /**
     * Notes:   获取商家信息
     * author: lfy
     * Date: 2021/11/22
     * Time: 18:04
     * @return array|bool|void
     * @throws GuzzleException
     */
    public function getSellerData()
    {
        return $this->get('open.user.seller.get');
    }


    private function _getRedisManager(): RedisManager
    {
        return app(RedisManager::class);
    }

    private function _getAccessTokenKey(string $shopId): string
    {
        return "platform_auth:kwaixiaodian:access_token:${shopId}";
    }

    private function _getRefreshTokenKey($shopId): string
    {
        return "platform_auth:kwaixiaodian:refresh_token:${shopId}";
    }

    /**
     * Notes: 设置缓存
     * author: lfy
     * Date: 2021/11/19
     * Time: 17:20
     * @param $TokenData
     * @return bool
     */
    public function setAccessTokenCache($tokenData): bool
    {
        $redisManager = $this->_getRedisManager();
        try {
            $accessToken        = $tokenData['access_token'];
            $refreshToken       = $tokenData['refresh_token'];
            $expiresIn          = $tokenData['expires_in'];
            $refreshExpiresIn   = $tokenData['refresh_token_expires_in'];
            $shopId             = $tokenData['open_id'];
            $userId             = $tokenData['user_id'] ?? 0;
            $id                 = $tokenData['id'] ?? 0;
            $shopName           = $tokenData['shop_name'] ?? $shopId;
            $isCb               = $tokenData['is_cb'] ?? 0;
            $isGlobal           = $tokenData['is_global'] ?? 0;
            $minRefreshLeftTime = 24 * 3600;//  30 minutes before the token expires
            $expiresIn          -= $minRefreshLeftTime;
            $refreshExpiresIn   -= $minRefreshLeftTime;
            $redisManager->pipeline(function ($pipe) use ($tokenData,$shopId, $accessToken, $expiresIn, $refreshExpiresIn, $refreshToken, $userId, $id, $shopName,$isCb,$isGlobal) {
                $accessTokenKey = $this->_getAccessTokenKey($id);
                $cacheData      = array_merge($tokenData,[
                    'access_token' => $accessToken,
                    'shop_id'      => $shopId,
                    'user_id'      => $userId,
                    'id'           => $id,
                    'shop_name'    => $shopName,
                    'is_cb'        => $isCb,
                    'is_global'    => $isGlobal
                ]);
                $pipe->set($accessTokenKey, json_encode($cacheData));
                $pipe->expire($accessTokenKey, $expiresIn);
                $refreshTokenKey = $this->_getRefreshTokenKey($id);
                unset($cacheData['access_token']);
                $cacheData['refresh_token'] = $refreshToken;
                $pipe->set($refreshTokenKey, json_encode($cacheData));
                $pipe->expire($refreshTokenKey, $refreshExpiresIn);
            });
            return true;
        } catch (Exception $e) {
            \Log::channel('kwaixiaodianServers')->error('设置快手 AccessToken到缓存异常', ['msg' => $e->getMessage(), 'token_data' => $tokenData]);
            return false;
        }
    }

    /**
     * Notes: 从缓存中获取 AccessToken
     * author: lfy
     * Date: 2021/11/10
     * Time: 16:30
     * @param string $shopId
     * @param string $func
     * @return mixed|string
     * @throws GuzzleException
     */
    public function getAccessTokenBySellerId(string $shopId, $func = '')
    {
        $redisManager   = $this->_getRedisManager();
        $accessTokenKey = $this->_getAccessTokenKey($shopId);
        $accessToken    = $redisManager->get($accessTokenKey);
        // AccessToken 过期
        if (empty($accessToken)) {
            $refreshTokenKey = $this->_getRefreshTokenKey($shopId);
            $refreshToken    = json_decode($redisManager->get($refreshTokenKey), true);
            // RefreshToken 过期
            $tokenData = [];
            if (!empty($refreshToken) && isset($refreshToken['refresh_token'])) {
                $tokenData              = $this->refreshToken($refreshToken['refresh_token']);
                $accessToken            = array_merge($refreshToken,[
                    'access_token' => $tokenData['access_token'] ?? ''
                ]);
                $tokenData['open_id']   = $refreshToken['shop_id'];
                $tokenData['user_id']   = $refreshToken['user_id'];
                $tokenData['id']        = $refreshToken['id'];
                $tokenData['shop_name'] = $refreshToken['shop_name'];
                $tokenData['is_global'] = $accessToken['is_global'];
                $tokenData['is_cb']     = $accessToken['is_cb'];
                $tokenData = array_merge($refreshToken,$tokenData);
                $this->setAccessTokenCache($tokenData);
            }
            if (is_callable($func)) $func($tokenData);
        }
        return $accessToken;
    }

    public function getRedisKey($shopId = '*')
    {
        $redisManager   = $this->_getRedisManager();
        $accessTokenKey = $this->_getAccessTokenKey($shopId);
        return $redisManager->keys($accessTokenKey);
    }
}
